﻿//http://devblog.phillipspiess.com/2010/02/23/better-know-an-algorithm-1-marching-squares/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
namespace MathEvaluator_Grapher
{
    class MarchingSquares
    {
      /*  private enum StepDirection
        {
            None,
            Up,
            Left,
            Down,
            Right
        }
        public static float MARCHING_PRECISION = 0.01f;
        public static Vector2 FindStartPoint(MathEvaluator_Grapher.GrapherFunction.Vector3Color data,float isoline)
        {

        }*/

        /// <summary>
        /// Linearly interpolate the position where an isosurface cuts
        /// an edge between two vertices, each with their own scalar value
        /// </summary>
        static Vector2 VertexInterp(int i,int j,int edge1,int edge2,Vector2 vStart,Vector2 vStep,float[,] datablock, float isolevel)
        {
                   /*
                    Vector(x,y) = start
                    1 [i - 1, j] : 1;
                    2 [i, j] : 2;
                    4 [i, j - 1] : 4;
                    8 [i - 1, j - 1] : 8;
                     */
            int x1, x2, y1, y2;
            #region "Deconstruct edges"
            switch (edge1)
            { 
                case 1:
                    x1 = i - 1;
                    y1 = j;
                    break;
                case 2:
                    x1 = i;
                    y1 = j;
                    break;
                case 4:
                    x1 = i;
                    y1 = j - 1;
                    break;
                case 8:
                    x1 = i - 1;
                    y1 = j - 1;
                    break;
                default:
                    throw new Exception();
            }
            switch (edge2)
            {
                case 1:
                    x2 = i - 1;
                    y2 = j;
                    break;
                case 2:
                    x2 = i;
                    y2 = j;
                    break;
                case 4:
                    x2 = i;
                    y2 = j - 1;
                    break;
                case 8:
                    x2 = i - 1;
                    y2 = j - 1;
                    break;
                default:
                    throw new Exception();
            }
            #endregion
            Vector2 p1 = vStart, p2 = vStart;
            p1.X += vStep.X * x1;
            p1.Y += vStep.Y * y1;

            p2.X += vStep.X * x2;
            p2.Y += vStep.Y * y2;
            float valp1 = datablock[x1,y1];
            float valp2 = datablock[x2,y2];
            float mu;
            Vector2 p = Vector2.Zero;

            if (Math.Abs(isolevel - valp1) < 0.00001)
                return (p1);
            if (Math.Abs(isolevel - valp2) < 0.00001)
                return (p2);
            if (Math.Abs(valp1 - valp2) < 0.00001)
                return (p1);

            mu = (isolevel - valp1) / (valp2 - valp1);
            p.X = p1.X + mu * (p2.X - p1.X);
            p.Y = p1.Y + mu * (p2.Y - p1.Y);
            return (p);
        }
        
        public static List<Vector2> Polygonise(float[,] datablock, float isolevel, Vector2 vStart, Vector2 vStep, int steps)
        {
            bool[,] bitmap = new bool[steps, steps];
            byte[,] bytemap = new byte[steps - 1, steps - 1];
            for (int i = 0; i < steps; i++)
                for (int j = 0; j < steps; j++)
                    bitmap[i,j]= datablock[i, j] > isolevel;
            for (int i = 1; i < steps ; i++)
                for (int j = 1; j < steps ; j++)
                {
                    int value = bitmap[i - 1, j] ? 0 : 1;
                    value |= bitmap[i, j] ? 0 : 2;
                    value |= bitmap[i, j - 1] ? 0 : 4;
                    value |= bitmap[i - 1, j - 1] ? 0 : 8;
                    bytemap[i - 1,j - 1] = (byte)value;

                }
            //3 2
            //0 1
            List<Vector2> lineList = new List<Vector2>();
             for (int i = 1; i < steps ; i++)
                for (int j = 1; j < steps ; j++)
                {
                    /*
                    Vector(x,y) = start
                    1 [i - 1, j] : 1;
                    2 [i, j] : 2;
                    4 [i, j - 1] : 4;
                    8 [i - 1, j - 1] : 8;
                     */


                    switch (bytemap[i -1, j -1])
                    {
                        case 1:
                            lineList.Add(VertexInterp(i,j,8,1,vStart,vStep,datablock,isolevel));
                            lineList.Add(VertexInterp(i,j,1,2,vStart,vStep,datablock,isolevel));
                            break;
                        case 2:
                            lineList.Add(VertexInterp(i, j, 1, 2, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 2, 4, vStart, vStep, datablock, isolevel));
                            break;
                        case 3:
                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 4, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 4:
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 4, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 5:
                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));

                            lineList.Add(VertexInterp(i, j, 1, 2, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 2, 4, vStart, vStep, datablock, isolevel));
                            break;
                        case 9:
                        case 6:
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 1, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 7:
                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));
                            break;
                        case 8:
                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));
                            break;
                        case 10:
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 4, 2, vStart, vStep, datablock, isolevel));

                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 1, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 11:
                            lineList.Add(VertexInterp(i, j, 8, 4, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 4, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 12:
                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 4, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 13:
                            lineList.Add(VertexInterp(i, j, 1, 2, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 4, 2, vStart, vStep, datablock, isolevel));
                            break;
                        case 14:
                            lineList.Add(VertexInterp(i, j, 8, 1, vStart, vStep, datablock, isolevel));
                            lineList.Add(VertexInterp(i, j, 1, 2, vStart, vStep, datablock, isolevel));
                            break;
                        default:
                            break;
                    }
                }
             return lineList;

        }
    }
}